package mgoDB

import (
	"context"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/x/bsonx"
	"strconv"
	"sync"
	"time"
)

var (
	contentMap = sync.Map{}     //数据库
	contentMu sync.Mutex        //数据库锁定防止并发访问
)

//MgoContent 数据库上下文
type MgoContent struct {
	collectionMap map[string]IMgoRepository
}

//DataBaseMapping 添加映射
// @client      连接对象
// @dataName    数据库名
// @createIndex 数据库表索引
func DataBaseMapping(mappingName string,configFn func(mappingName string) map[string]string,createIndexFn func()map[string][]IndexItem) (*MgoContent,error) {
	value, ok := contentMap.Load(mappingName)
	if ok {
		return value.(*MgoContent), nil
	}
	contentMu.Lock()
	defer contentMu.Unlock()

	value, ok = contentMap.Load(mappingName)
	if ok {
		return value.(*MgoContent), nil
	}

	config := configFn(mappingName)
	timeout := time.Second * 30
	if timeoutStr, ok := config["timeout"]; ok {
		atoi, err := strconv.Atoi(timeoutStr)
		if err == nil {
			timeout = time.Second * time.Duration(atoi)
		}
	}
	client, err := GetMgoClient(config)
	if err != nil {
		return nil, err
	}
	dbname := config["dbname"]
	database := client.Database(dbname)
	content := &MgoContent{
		collectionMap: map[string]IMgoRepository{},
	}
	collectionIndexMap := createIndexFn()
	for key, val := range collectionIndexMap {
		collection := database.Collection(key)
		repository := &MgoRepository{
			database:   database,
			collection: collection,
			timeout:    timeout,
		}
		//设置集合
		content.collectionMap[key] = repository
		//添加映射
		content.addMapping(collection, val)
	}
	contentMap.Store(mappingName, content)
	return content, nil
}

//IndexItem 索引项
type IndexItem struct {
	Elems  []string  //字段
	Unique bool      //是否唯一
	Desc   bool      //是否降序
}

//AddMapping 添加映射
func (m *MgoContent) addMapping(collection *mongo.Collection,indexItems []IndexItem) {
	indexModels := make([]mongo.IndexModel,len(indexItems))
	for key,val := range indexItems{
		bson := bsonx.Doc{}
		for _, elem := range val.Elems {
			if val.Desc {
				bson = bson.Append(elem, bsonx.Int32(-1))
				continue
			}
			bson = bson.Append(elem, bsonx.Int32(1))
		}
		// 设置索引
		indexModels[key] =  mongo.IndexModel{
			Keys:    bson,
			Options: options.Index().SetUnique(val.Unique),
		}
	}
	//创建索引
	collection.Indexes().CreateMany(context.Background(),indexModels)
}

// GetMgoRepository 获取集合仓储
// collectionName  结构体
func (m *MgoContent) GetMgoRepository(collectionName string) (IMgoRepository,bool) {
	repository, ok := m.collectionMap[collectionName]
	return repository, ok
}

